#include <kaleidoscope/frontend/lexical_analysis/lexer.hpp>
//=====================================================================
#include <atma/assert.hpp>
//=====================================================================
#include <kaleidoscope/common/symbol_ids.hpp>
#include <kaleidoscope/common/channels.hpp>
//=====================================================================
using namespace kal;
//=====================================================================


bool main_lexer::next_token_()
{
	const atma::sooty::lexer_buffer::char_type& c = get_current_char();
	
	// first, whitespace
	if ( c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' )
		whitespace();

	// next, simple things
	else if (match_if(';'))
		create_token<std::string>(ids::semi, channels::code);
	else if (match_if('{'))
		create_token<std::string>(ids::lcurly, channels::code);
	else if (match_if(','))
		create_token<std::string>(ids::comma, channels::code);
	else if (match_if('}'))
		create_token<std::string>(ids::rcurly, channels::code);
	else if (match_if('('))
		create_token<std::string>(ids::lparen, channels::code);
	else if (match_if(')'))
		create_token<std::string>(ids::rparen, channels::code);
	else if (match_if('+'))
		create_token<std::string>(ids::plus_sign, channels::code);
	else if (match_if('-'))
		create_token<std::string>(ids::minus_sign, channels::code);
	else if (match_if('*'))
		create_token<std::string>(ids::star_sign, channels::code);
	else if (match_if('/'))
		create_token<std::string>(ids::fwd_slash, channels::code);
	else if ( in_range(c, '0', '9') )
		number();
	
	// more complex things
	else if ( in_range(c, 'a', 'z') || in_range(c, 'A', 'Z') || c == '_' )
		identifier();
	
	// no match!?
	else
		ATMA_ASSERT(false && "unidentified character");
	
	return true;
}


void main_lexer::whitespace()
{
	// first, simple spaces and tabs
	if (match_if(' ') || match_if('\t') || match_if('\f'))
	{
	}
	// now, return values
	else if (match_if('\r'))
	{
		match_if('\n');
		newline();
	}
	else if (match_if('\n'))
	{
		match_if('\n');
		newline();
	}
	
	create_token<std::string>(ids::whitespace, channels::whitespace);
}

void main_lexer::identifier()
{
	// yay shortcutting
	match_if('_') || match_in_range('a', 'z') || match_in_range('A', 'Z');
	
	// yay simplicity
	while ( match_if('_') || match_in_range('a', 'z') || match_in_range('A', 'Z') || match_in_range('0', '9') )
		;
	
	// yay creation
	resolve_identifier_as_keyword(get_current_lexeme());
}

void main_lexer::resolve_identifier_as_keyword(const std::string& id)
{
	if (id == "int")
		create_token<std::string>(ids::int_keyword, channels::code);
	else if (id == "void")
		create_token<std::string>(ids::void_keyword, channels::code);
	else if (id == "function")
		create_token<std::string>(ids::function_keyword, channels::code);
	else if (id == "return")
		create_token<std::string>(ids::return_keyword, channels::code);
	else
		create_token<std::string>(ids::identifier, channels::code);
}

void main_lexer::number()
{
	while (match_in_range('0', '9'))
		;
	
	create_token<int>(ids::int_literal, channels::code);
}